This page was generated from docs/examples/DataSet/Offline plotting with categorical data.ipynb. Interactive online version: Binder badge.

Offline plotting with categorical data

This notebook is a collection of plotting examples using the plot_dataset function and caterogical (string-valued) data. The notebook should cover all possible permutations of categorical versus numerical data.

[1]:
%matplotlib inline
from pathlib import Path

import numpy as np

from qcodes.dataset import (
    Measurement,
    initialise_or_create_database_at,
    load_or_create_experiment,
    plot_dataset,
)
from qcodes.parameters import Parameter
Logging hadn't been started.
Activating auto-logging. Current session state plus future input saved.
Filename       : /home/runner/.qcodes/logs/command_history.log
Mode           : append
Output logging : True
Raw input log  : False
Timestamping   : True
State          : active
Qcodes Logfile : /home/runner/.qcodes/logs/240905-16154-qcodes.log
[2]:
initialise_or_create_database_at(Path.cwd() / "offline_plotting_example_categorical.db")
exp = load_or_create_experiment("offline_plotting_experiment", "nosample")

1D plotting

Category is the independent parameter

With the category as the independent parameter, plot_dataset will default to a bar plot as long as there is at most one value per category. If more than one value is found for any category a bar plot is not possible, and the plot_dataset falls back to a scatter plot.

[3]:
voltage = Parameter("voltage", label="Voltage", unit="V", set_cmd=None, get_cmd=None)
fridge_config = Parameter(
    "config", label="Fridge configuration", set_cmd=None, get_cmd=None
)

meas = Measurement(exp=exp)
meas.register_parameter(fridge_config, paramtype="text")
meas.register_parameter(voltage, setpoints=(fridge_config,))

with meas.run() as datasaver:
    configurations = ["open", "outer chamber closed", "pumping", "closed"]

    for configuration in configurations:
        datasaver.add_result(
            (fridge_config, configuration), (voltage, np.random.rand())
        )

dataset = datasaver.dataset
Starting experimental run with id: 1.
[4]:
_ = plot_dataset(dataset)
../../_images/examples_DataSet_Offline_plotting_with_categorical_data_6_0.png
[5]:
with meas.run() as datasaver:
    configurations = ["open", "outer chamber closed", "pumping", "closed"]

    for configuration in configurations:
        datasaver.add_result(
            (fridge_config, configuration), (voltage, np.random.rand())
        )

    datasaver.add_result((fridge_config, "open"), (voltage, np.random.rand()))

dataset = datasaver.dataset

_ = plot_dataset(dataset)
Starting experimental run with id: 2.
../../_images/examples_DataSet_Offline_plotting_with_categorical_data_7_1.png

Category is the dependent parameter

With the categories as the dependent variable, i.e., the outcome of a measurement, the plot_dataset defaults to a scatter plot.

Here is an example with made-up parameters and random values.

UNRESOLVED: How do we ensure the y-axis order?

[6]:
voltage = Parameter("voltage", label="Voltage", unit="V", set_cmd=None, get_cmd=None)
response = Parameter("response", label="Sample response", set_cmd=None, get_cmd=None)

meas = Measurement(exp=exp)
meas.register_parameter(voltage)
meas.register_parameter(response, paramtype="text", setpoints=(voltage,))


with meas.run() as datasaver:
    for volt in np.linspace(0, 1, 50):
        coinvalue = volt + 0.5 * np.random.randn()
        if coinvalue < 0:
            resp = "Bad"
        elif coinvalue < 0.8:
            resp = "Good"
        else:
            resp = "Excellent"

        datasaver.add_result((voltage, volt), (response, resp))

dataset = datasaver.dataset
Starting experimental run with id: 3.
[7]:
_ = plot_dataset(dataset)
../../_images/examples_DataSet_Offline_plotting_with_categorical_data_10_0.png

Both variables are categorical

For both variables being categorical, the plot_dataset defaults to a scatter plot.

This case would typically be some summary of a large number of measurements.

[8]:
sample = Parameter("sample", label="Sample", unit="", set_cmd=None, get_cmd=None)
feature = Parameter("feature", label="Physical feature", set_cmd=None, get_cmd=None)

meas = Measurement(exp=exp)
meas.register_parameter(sample, paramtype="text")
meas.register_parameter(feature, paramtype="text", setpoints=(sample,))


with meas.run() as datasaver:
    features = ["superconducting", "qubit", "clean states", "high bandwidth"]

    for samp in ["Nanowire", "Silicon Chip", "SQUID", "Membrane"]:
        feats = np.random.randint(1, 5)
        for _ in range(feats):
            datasaver.add_result(
                (sample, samp), (feature, features[np.random.randint(0, 4)])
            )

dataset = datasaver.dataset
Starting experimental run with id: 4.
[9]:
_ = plot_dataset(dataset)
../../_images/examples_DataSet_Offline_plotting_with_categorical_data_13_0.png

2D plotting

Naming convention: the x-axis is horizontal, the y-axis is vertical, and the z-axis is out-of-plane.

Categorical data on the x-axis

Here is an example where different samples are tested for conductivity. The longer the name of the sample, the higher the conductivity.

[10]:
sample = Parameter("sample", label="Sample", unit="", set_cmd=None, get_cmd=None)
gate_voltage = Parameter(
    "gate_v", label="Gate voltage", unit="V", set_cmd=None, get_cmd=None
)
conductance = Parameter(
    "conductance", label="Conductance", unit="e^2/hbar", set_cmd=None, get_cmd=None
)

meas = Measurement(exp=exp)
meas.register_parameter(sample, paramtype="text")
meas.register_parameter(gate_voltage)
meas.register_parameter(conductance, setpoints=(sample, gate_voltage))


with meas.run() as datasaver:
    for samp in ["Nanowire", "Silicon Chip", "SQUID", "Membrane"]:
        gate_vs = np.linspace(0, 0.075, 75)

        for gate_v in gate_vs:
            datasaver.add_result(
                (sample, samp),
                (gate_voltage, gate_v),
                (conductance, len(samp) * gate_v),
            )

dataset = datasaver.dataset
Starting experimental run with id: 5.
[11]:
ax, _ = plot_dataset(dataset)
../../_images/examples_DataSet_Offline_plotting_with_categorical_data_17_0.png

Categorical data on the y-axis

This situation is very similar to having categorical data on the x-axis. We reuse the same example.

[12]:
sample = Parameter("sample", label="Sample", unit="", set_cmd=None, get_cmd=None)
gate_voltage = Parameter(
    "gate_v", label="Gate voltage", unit="V", set_cmd=None, get_cmd=None
)
conductance = Parameter(
    "conductance", label="Conductance", unit="e^2/hbar", set_cmd=None, get_cmd=None
)

meas = Measurement(exp=exp)
meas.register_parameter(sample, paramtype="text")
meas.register_parameter(gate_voltage)
meas.register_parameter(conductance, setpoints=(gate_voltage, sample))


with meas.run() as datasaver:
    for samp in ["Nanowire", "Silicon Chip", "SQUID", "Membrane"]:
        gate_vs = np.linspace(0, 0.01, 75)

        for gate_v in gate_vs:
            datasaver.add_result(
                (sample, samp),
                (gate_voltage, gate_v),
                (conductance, len(samp) * gate_v),
            )

dataset = datasaver.dataset
Starting experimental run with id: 6.
[13]:
ax, _ = plot_dataset(dataset)
../../_images/examples_DataSet_Offline_plotting_with_categorical_data_20_0.png

Categorical data on the z-axis

Categorical data on the z-axis behaves similarly to numerical data on the z-axis; what kind of plot we get depends on the structure of the setpoints (i.e. the x-axis and y-axis data). If the setpoints are on a grid, we get a heatmap. If not, we get a scatter plot.

Gridded setpoints

[14]:
bias_voltage = Parameter(
    "bias_v", label="Bias voltage", unit="V", set_cmd=None, get_cmd=None
)
gate_voltage = Parameter(
    "gate_v", label="Gate voltage", unit="V", set_cmd=None, get_cmd=None
)
useful = Parameter(
    "usefulness", label="Usefulness of region", set_cmd=None, get_cmd=None
)

meas = Measurement(exp=exp)
meas.register_parameter(gate_voltage)
meas.register_parameter(bias_voltage)
meas.register_parameter(
    useful, setpoints=(bias_voltage, gate_voltage), paramtype="text"
)


# a function to simulate the usefulness of a region


def get_usefulness(x, y):
    val = np.sin(x) * np.sin(y)
    if val < -0.4:
        return "Useless"
    if val < 0:
        return "Bad"
    if val < 0.5:
        return "Possible"
    return "Good"


with meas.run() as datasaver:
    for bias_v in np.linspace(0, 3, 100):
        for gate_v in np.linspace(-1, 1, 75):
            datasaver.add_result(
                (bias_voltage, bias_v),
                (gate_voltage, gate_v),
                (useful, get_usefulness(bias_v, gate_v)),
            )

dataset = datasaver.dataset
Starting experimental run with id: 7.
[15]:
ax, cax = plot_dataset(dataset)
../../_images/examples_DataSet_Offline_plotting_with_categorical_data_24_0.png

Scattered setpoints

The same example as above, but this time with setpoints not on a grid.

[16]:
bias_voltage = Parameter(
    "bias_v", label="Bias voltage", unit="V", set_cmd=None, get_cmd=None
)
gate_voltage = Parameter(
    "gate_v", label="Gate voltage", unit="V", set_cmd=None, get_cmd=None
)
useful = Parameter(
    "usefulness", label="Usefulness of region", set_cmd=None, get_cmd=None
)

meas = Measurement(exp=exp)
meas.register_parameter(gate_voltage)
meas.register_parameter(bias_voltage)
meas.register_parameter(
    useful, setpoints=(bias_voltage, gate_voltage), paramtype="text"
)


# a function to simulate the usefulness of a region


def get_usefulness(x, y):
    val = np.sin(x) * np.sin(y)
    if val < -0.4:
        return "Useless"
    if val < 0:
        return "Bad"
    if val < 0.5:
        return "Possible"
    return "Good"


with meas.run() as datasaver:
    for bias_v in 3 * (np.random.rand(100)):
        for gate_v in 2 * (np.random.rand(75) - 0.5):
            datasaver.add_result(
                (bias_voltage, bias_v),
                (gate_voltage, gate_v),
                (useful, get_usefulness(bias_v, gate_v)),
            )

dataset = datasaver.dataset
Starting experimental run with id: 8.
[17]:
ax, cax = plot_dataset(dataset)
../../_images/examples_DataSet_Offline_plotting_with_categorical_data_27_0.png

Categorical data on x-axis and z-axis

For completeness, we include two examples of this situation. One resulting in a grid and one resulting in a scatter plot. We reuse the example with the x- and y-axes having numerical data with just a slight modification.

[18]:
sample = Parameter("sample", label="Sample", set_cmd=None, get_cmd=None)
gate_voltage = Parameter(
    "gate_v", label="Gate voltage", unit="V", set_cmd=None, get_cmd=None
)
useful = Parameter(
    "usefulness", label="Usefulness of region", set_cmd=None, get_cmd=None
)

meas = Measurement(exp=exp)
meas.register_parameter(sample, paramtype="text")
meas.register_parameter(gate_voltage)
meas.register_parameter(useful, setpoints=(sample, gate_voltage), paramtype="text")

samples = ["nanowire", "2DEG", "spin qubit", "nanowire_alt"]

# a function to simulate the usefulness of a region


def get_usefulness(x, y):
    x_num = samples.index(x) * 4 / len(samples)
    val = np.sin(x_num) * np.sin(y)
    if val < -0.4:
        return "Useless"
    if val < 0:
        return "Bad"
    if val < 0.5:
        return "Possible"
    return "Good"


with meas.run() as datasaver:
    for samp in samples:
        for gate_v in np.linspace(-1, 1, 75):
            datasaver.add_result(
                (sample, samp),
                (gate_voltage, gate_v),
                (useful, get_usefulness(samp, gate_v)),
            )

dataset = datasaver.dataset
Starting experimental run with id: 9.
[19]:
ax, cax = plot_dataset(dataset)
../../_images/examples_DataSet_Offline_plotting_with_categorical_data_30_0.png
[20]:
sample = Parameter("sample", label="Sample", set_cmd=None, get_cmd=None)
gate_voltage = Parameter(
    "gate_v", label="Gate voltage", unit="V", set_cmd=None, get_cmd=None
)
useful = Parameter(
    "usefulness", label="Usefulness of region", set_cmd=None, get_cmd=None
)

meas = Measurement(exp=exp)
meas.register_parameter(sample, paramtype="text")
meas.register_parameter(gate_voltage)
meas.register_parameter(useful, setpoints=(sample, gate_voltage), paramtype="text")

samples = ["nanowire", "2DEG", "spin qubit", "nanowire_alt"]

# a function to simulate the usefulness of a region


def get_usefulness(x, y):
    x_num = samples.index(x) * 4 / len(samples)
    val = np.sin(x_num) * np.sin(y)
    if val < -0.4:
        return "Useless"
    if val < 0:
        return "Bad"
    if val < 0.5:
        return "Possible"
    return "Good"


with meas.run() as datasaver:
    for samp in samples:
        for gate_v in 2 * (np.random.rand(75) - 0.5):
            datasaver.add_result(
                (sample, samp),
                (gate_voltage, gate_v),
                (useful, get_usefulness(samp, gate_v)),
            )

dataset = datasaver.dataset
Starting experimental run with id: 10.
[21]:
ax, cax = plot_dataset(dataset)
../../_images/examples_DataSet_Offline_plotting_with_categorical_data_32_0.png
[ ]: